#include "blsvn.h"
#include "help.h"

const char* HelpMain =
"\bblsvn v0.0 - simple path expansion wrapper around svn.exe \n"
"\n"
"blsvn passes its arguments on to svn.exe, except that any argument \n"
"starting with '~' is presumed to be a special abbreviation for a \n"
"repository directory, and will be expanded before passing to svn.exe.  \n"
"\n"
"\bDefining Abbreviations\n"
"    Use blsvn's 'set' subcommand to create an abbreviation that\n"
"refers to any particular directory in any repository. Example:\n"
"\tblsvn set ~chrome http://src.chromium.org/svn/trunk/src\n"
"\tblsvn list ~chrome/build\n"
"As a convenience, a separate subcommand called 'cd' lets you\n"
"display and change the null abbreviation name '~'. For example:\n"
"\tblsvn set apache http://svn.apache.org/repos/asf\n"
"\tblsvn cd ~apache\n"
"\t# now '~' is set to 'http://svn.apache.org/repos/asf'\n"
"\tblsvn ls ~\n"
"\tblsvn cd ~/xalan/c/trunk\n"
"\tblsvn ls ~\n"
"\tblsvn cat ~/README\n"
"\n"
"\bDot-Relative Abbreviations\n"
"    Often, one wants to refer to the repository directory associated\n"
"with the current directory in the working copy.  The abbreviation '~.'\n"
"provides just that ability.  However, you can also put any number of\n"
"dots after the '~' to refer arbitrarily higher in the repository\n"
"hierarchy. The canonical example is: \n"
"\tblsvn copy ~../trunk ~../tags/NewTag\n"
"Note: your current working directory (\".\") must be a working copy\n"
"for dot-relative abbreviations to work -- that's how blsvn locates\n"
"the repository.\n"
"As another example, if you understand that this command:\n"
"\tblsvn ls ~..\n"
"is equivalent to typing the following two commands:\n"
"\tblsvn cd .\n"
"\tblsvn ls ~/..\n"
"then you probably understand all you need to know about blsvn.\n"
"    Note that any argument starting with a tilde ('~') ALWAYS refers to\n"
"a repository path. However, both the 'cd' and 'set' subcommands will\n"
"accept a working copy path, which will be interpreted as referring\n"
"to the analogous path in the corresponding repository. Example:\n"
"\tblsvn cd .\n"
"\t# list repo copy of current directory\n"
"\tblsvn ls ~\n"
"\n"
"\bSource Code\n"
"    The source code is insanely Windows-specific, and was built with the\n"
"free command-line compiler (v14) that Microsoft offers. It is offered under\n"
"the very simple and constraint-free MIT License (see license.txt in\n"
"the source). For project info and source code, go here:\n"
"\thttp://code.google.com/p/blsvn/\n"
"\n"
"\bMiscellaneous\n"
"    To install blsvn, just put blsvn.exe in any writable directory in your\n"
"executable search paths.  blsvn will look for svn.exe in all the usual\n"
"places. If it cannot be located, blsvn will tell you how to use the \"set\"\n"
"command once to manually set the location of svn.exe.\n"
"\n"
"For more details on any blsvn subcommand, enter:\n"
"\tblsvn help [set|cd]\n"
"\n"
"If the first argument to blsvn is a single dash (\"-\"), it will echo\n"
"the command-line it is internally passing to svn.exe (if any), but won't\n"
"actually do anything. If you're not sure exactly what some '~'\n"
"abbreviation expands to, this is a harmless way to check first.\n"
"\n"
"blsvn does not deal with authentication, so if you get an error message\n"
"of that type, just login using svn first to cache your credentials.\n"
"\n"
"Please email bugs/comments/whatever to blsvn@burklabs.com.\n"
"http://www.burklabs.com/blsvn\n"
"Copyright (C) 2010, Ron Burk.\n"
;

const char* HelpSet =
"\bset - set internal blsvn variables.\n"
"\n"
"\bSyntax:\n"
"\tblsvn set [name [value]]\n"
"\bDescription:\n"
"    The 'set' command is used to set or display named strings that\n"
"are retained across invocations of blsvn. Usually, these names start\n"
"with a tilde ('~'), the syntax for defining repository path abbreviations.\n"
"For example:\n"
"\tblsvn set ~apache http://svn.apache.org/repos/asf\n"
"defines \"~apache\" to be the path to an Apache SVN repository. That\n"
"abbreviation will then be expanded in later blsvn commands:\n"
"\tblsvn list ~apache\n"
"\tblsvn list ~apache/xalan\n"
"Giving the 'set' subcommand with no arguments prints out a list of all\n"
"the named strings and their values.\n"
"\bOther Uses:\n"
"    There is exactly one named string available that does not start\n"
"with a '~' and is not a simple repository path abbreviations. The named\n"
"value 'SvnExePath', if you set it to the path of a valid Windows executable,\n"
"will be used to locate the copy of svn.exe that you want blsvn to use.\n"
"\n"
;
const char* HelpCd =
"\bcd - change/view the blsvn current repository directory.\n"
"\n"
"\bSyntax:\n"
"\tblsvn cd [path]\n"
"\bDescription:\n"
"    Sets or displays blsvn's \"current repository directory\", which can\n"
"be referred to with the syntax \"~\". For example, this pair of commands:\n"
"\tblsvn set ~chrome http://src.chromium.org/svn/trunk/src\n"
"\tblsvn list ~chrome/build\n"
"is equivalent to this pair of commands:\n"
"\tblsvn cd http://src.chromium.org/svn/trunk/src\n"
"\tblsvn list ~/build\n"
"This syntax makes it easier to traverse and operate on directories\n"
"in remote repositories. For example,\n"
"\tblsvn cd http://svn.apache.org/repos/asf\n"
"\tblsvn ls ~\n"
"\tblsvn cd ~/xalan/c/trunk\n"
"\tblsvn ls ~\n"
"\tblsvn cd ~/..\n"
"\tblsvn ls ~\n"
"Note that the 'cd' subcommand is essentially the same as using the 'set'\n"
"subcommand to assign an abbreviation to the name '~'.\n"
"    The optional path can be a repository directory, a repository directory\n"
"abbreviation, or a path to a local working copy. In the latter case, cd\n"
"will set '~' to the repository directory associated with the given local\n"
"working copy directory.\n"
"    Using the 'cd' subcommand with no arguments simply prints the current\n"
"value of the \"current repository directory\"\n"
"\n"
;

static
int     CtrlEvent;
static
DWORD   ConsoleMode;
static
WORD    Original;

BOOL WINAPI CtrlHandler(DWORD Event)
    {
    CtrlEvent   = TRUE;

    SetConsoleMode(WcStdin, ConsoleMode);
    SetConsoleTextAttribute(WcStdout, Original);

    /* if it was CTRL-C, we handled it */
    return (Event == CTRL_C_EVENT);
    }
    
void    HelpEmit(const char* HelpText)
    {
    BOOL                        Status;
    WORD                        Default, Bold, Computer;
    CONSOLE_SCREEN_BUFFER_INFO  ConsoleInfo;
    int                         Pagination;
    int                         Line;
    int                         Quit    = FALSE;

    if(GetFileType(WcStdout) != FILE_TYPE_CHAR)
        {
        DWORD   Dummy = 0;
        
        WriteFile(WcStdout, HelpText, lstrlen(HelpText), &Dummy, NULL);
        return;
        }
    Status = SetConsoleCtrlHandler(CtrlHandler, TRUE);
    WCASSERT(Status != FALSE);
    Default = BACKGROUND_BLUE|FOREGROUND_INTENSITY|FOREGROUND_GREEN|FOREGROUND_RED;
    Bold    = BACKGROUND_BLUE|FOREGROUND_INTENSITY|FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_BLUE;
    Computer= BACKGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_BLUE;
    GetConsoleScreenBufferInfo(WcStdout, &ConsoleInfo);
    GetConsoleMode(WcStdin, &ConsoleMode);
//    SetConsoleMode(WcStdin, (ConsoleMode & ~(ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT)) | ENABLE_WINDOW_INPUT);
    SetConsoleMode(WcStdin, (ConsoleMode & ~(ENABLE_ECHO_INPUT)));
    Original    = ConsoleInfo.wAttributes;
    Pagination  = ConsoleInfo.srWindow.Bottom - ConsoleInfo.srWindow.Top;
    SetConsoleTextAttribute(WcStdout, Default);
    for(Line = 0; *HelpText && !Quit; ++HelpText)
        {
        if(CtrlEvent)
            WcExit(0);
        if(*HelpText == '\b')
            {
            SetConsoleTextAttribute(WcStdout, Bold);
            }
        else if(*HelpText == '\t')
            {
            WcPrintfW(L"    ");
            SetConsoleTextAttribute(WcStdout, Computer);
            }
        else if(*HelpText == '\n')
            {
            SetConsoleTextAttribute(WcStdout, Default);
            WcPrintfW(L"\n");
            ++Line;
            if(Line && !(Line%Pagination))
                {
                INPUT_RECORD    Event;
                DWORD           EventCount;
                
                Status = FlushConsoleInputBuffer(WcStdin);
                WCASSERT(Status != FALSE);
                GetNumberOfConsoleInputEvents(WcStdin, &EventCount);
                WCASSERT(EventCount == 0);
                GetConsoleScreenBufferInfo(WcStdout, &ConsoleInfo);
                WcPrintfW(L"Press enter to continue...");
                
                while(!Quit)
                    {
                    if(CtrlEvent)
                        {
                        Quit    = TRUE;
                        continue;
                        }
                    EventCount=0;
                    Status = ReadConsoleInput(WcStdin, &Event, 1, &EventCount);
                    WCASSERT(Status != FALSE);
                    if(Event.EventType == KEY_EVENT)
                        {
                        KEY_EVENT_RECORD Key = Event.Event.KeyEvent;
                            
                        if(Key.bKeyDown == FALSE)
                            continue;
                        else if(Key.wVirtualKeyCode == VK_ESCAPE)
                            Quit    = TRUE;
                        else if(Key.wVirtualKeyCode == VK_RETURN)
                            break;
                        }
                    }
                Status = FlushConsoleInputBuffer(WcStdin);
                WCASSERT(Status != FALSE);
                SetConsoleCursorPosition(WcStdout, ConsoleInfo.dwCursorPosition);
                WcPrintfW(L"                           ");
                SetConsoleCursorPosition(WcStdout, ConsoleInfo.dwCursorPosition);
                }
            }
        else
            WcPrintfW(L"%c", *HelpText);
        }
    Status = SetConsoleCtrlHandler(NULL, FALSE);
    WCASSERT(Status != FALSE);

    SetConsoleMode(WcStdin, ConsoleMode);
    SetConsoleTextAttribute(WcStdout, Original);
    }

